package com.jeeplus.modules.statistics.service;

import com.google.common.collect.ImmutableMap;
import com.jeeplus.common.json.AjaxJson;
import com.jeeplus.common.utils.DateUtils;
import com.jeeplus.common.utils.StringUtils;
import com.jeeplus.common.utils.collection.CollectionUtil;
import com.jeeplus.common.utils.number.NumberUtil;
import com.jeeplus.common.utils.time.DateUtil;
import com.jeeplus.common.web.Result;
import com.jeeplus.database.datasource.annotation.DS;
import com.jeeplus.modules.statistics.model.enumeration.AppraiseLevelEnum;
import com.jeeplus.modules.statistics.model.constant.Constant;
import com.jeeplus.modules.statistics.model.enumeration.QueryParamsEnum;
import com.jeeplus.modules.statistics.common.SerialUtils;
import com.jeeplus.modules.statistics.mapper.*;
import com.jeeplus.modules.statistics.model.domain.*;
import com.jeeplus.modules.statistics.model.query.StatisticsQuery;
import com.jeeplus.modules.statistics.model.vo.HandleRankingVO;
import com.jeeplus.modules.statistics.model.vo.StatisticsXY;
import com.jeeplus.modules.statistics.model.vo.WaitingTimeVO;
import com.jeeplus.modules.sys.utils.UserUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 各区域窗口人员办件统计
 * 指定融合排号查询数据源[queuing]
 *
 * @author hanKongBin
 * @version 1.0
 * @date 2021/2/27 11:55
 */

@DS("queuing")
@Service
@RequiredArgsConstructor
@Slf4j
public class RegionalStaffStatisticsService {

    private final CounterService counterService;

    private final PiecesReceivedMapper piecesReceivedMapper;

    private final HotBusinessMapper hotBusinessMapper;

    private final BusinessTrendsMapper businessTrendsMapper;

    private final HandleRankingMapper handleRankingMapper;

    private final AppraiseMapper appraiseMapper;

    private final WaitingTimeMapper waitingTimeMapper;

    private final WeeklyTrafficMapper weeklyTrafficMapper;

    private final TimePeriodTrafficMapper timePeriodTrafficMapper;

    private final StaffPiecesReceivedMapper staffPiecesReceivedMapper;


    /**
     * 接件量统计
     *
     * @param query
     * @return
     */
    public Result<StatisticsXY> piecesReceivedStatistics(StatisticsQuery query) {
        List<String> xValue = new ArrayList<>();
        List<Long> yValue = new ArrayList<>();
        query.setUserid("%"+UserUtils.getUser().getId()+"%");
        try {
            List<PiecesReceivedCount> dataObj = piecesReceivedMapper.statistics(query);
            for (PiecesReceivedCount datum : dataObj) {
                StringBuilder xLabel = new StringBuilder();
                // 根据窗口id获取办理业务
                List<Counter> counters = counterService.findSerialNoByCounterId(datum.getCounterId(), query.getAreaId());
                if (CollectionUtil.isEmpty(counters)) {
                    continue;
                }
                String businessName = counters.stream().map(Counter::getTypename).collect(Collectors.joining(" "));
                // 拼接x轴 例:1号[社保服务]
                Optional.ofNullable(counters.get(0)).ifPresent(e -> xLabel.append(e.getCounterNo()).append("号"));
                xLabel.append("[").append(businessName).append("]");
                xValue.add(xLabel.toString());
                yValue.add(datum.getNumber());
            }

            // 汇总
            long count = dataObj.stream().mapToLong(PiecesReceivedCount::getNumber).sum();
            return Result.succeed(new StatisticsXY(xValue, yValue), "接件量获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("接件量分析失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 热度业务统计
     *
     * @param query
     * @return
     */
    public Result<StatisticsXY> hotBusStatistics(StatisticsQuery query) {
        List<String> xValue = new ArrayList<>();
        List<Long> yValue = new ArrayList<>();
        query.setUserid("%"+UserUtils.getUser().getId()+"%");
        try {
            List<HotBussinessCount> dataObj = hotBusinessMapper.statistics(query);
            for (HotBussinessCount datum : dataObj) {
                StringBuilder xLabel = new StringBuilder();
                // 拼接x轴数据 例:社保服务[1号、2号]
                Optional.ofNullable(datum.getBusName()).ifPresent(xLabel::append);
                Optional.ofNullable(datum.getBusChar()).ifPresent(e -> xLabel.append("(").append(e).append(")"));
                // 根据业务id查询办理窗口号
                List<String> counterNo = counterService.findCounterNoBySerialNo(SerialUtils.buildSerial(datum.getSerial(), 3), query.getAreaId());
                String counterName = counterNo.stream().map(e -> e + "号").collect(Collectors.joining(" "));
                xLabel.append("[").append(counterName).append("]");
                xValue.add(xLabel.toString());
                yValue.add(datum.getNumber());
            }
            // 汇总
            long count = dataObj.stream().mapToLong(HotBussinessCount::getNumber).sum();
            return Result.succeed(new StatisticsXY(xValue, yValue), "热度业务获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("热度业务分析失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 业务办理趋势统计
     * 1、获取去重后的历史办理时间，作为x轴数据
     * 2、统计各业务在不同时间的办件量
     * 3、组装y轴数据；格式：Map<String, long[]>
     *
     * @param query
     * @return
     */
    public Result<StatisticsXY> businessTrendsStatistics(StatisticsQuery query) {
        try {
            // 参数转换
            convertParams(query);
            query.setUserid("%"+UserUtils.getUser().getId()+"%");
            // 获取x轴的时间轴数据
            List<String> xValue = businessTrendsMapper.selectTimes(query);
            if (CollectionUtil.isEmpty(xValue)) {
                return Result.succeed("获取成功！");
            }
            // y轴数据实例
            List<StatisticsXY.StatisticsND> yValue = new ArrayList<>();
            // 统计各业务在不同时间的办件量
            List<BusinessTrends> trends = businessTrendsMapper.statistics(query).stream().filter(e -> StringUtils.isNotEmpty(e.getBusinessName())).collect(Collectors.toList());
            // 业务名称集合
            List<String> busNames = trends.stream().map(BusinessTrends::getBusinessName).collect(Collectors.toList());
            // 组织y轴数据
            // 循环业务名称
            for (String busName : busNames) {
                long[] yData = new long[xValue.size()];
                // 循环日期轴
                for (int i = 0; i < xValue.size(); i++) {
                    // 循环业务趋势
                    for (BusinessTrends trend : trends) {
                        if (xValue.get(i).equals(trend.getServerTime()) && busName.equals(trend.getBusinessName())) {
                            yData[i] = trend.getNumber();
                            break;
                        }
                    }
                }
                yValue.add(new StatisticsXY.StatisticsND(busName, yData));
            }
            // 汇总
            long count = trends.stream().mapToLong(BusinessTrends::getNumber).sum();
            return Result.succeed(new StatisticsXY(xValue, yValue), "获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("业务办理趋势分析失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 办件量排名
     *
     * @param query
     * @return
     */
    public Result<List<HandleRankingVO>> handleRanking(StatisticsQuery query) {
        List<HandleRankingVO> data = new ArrayList<>();
        try {
            query.setUserid("%"+UserUtils.getUser().getId()+"%");
            List<HandleRanking> rankings = handleRankingMapper.statistics(query);
            for (HandleRanking ranking : rankings) {
                // 获取窗口号
                List<String> counterNo = counterService.findCounterNoBySerialNo(SerialUtils.buildSerial(ranking.getSerialNo(), 3), query.getAreaId());
                // 构造前端响应实例
                data.add(HandleRankingVO.builder().counterNo(counterNo.stream().map(e -> e + "号").collect(Collectors.joining(" ")))
                        .busChar(ranking.getBusChar())
                        .busName(ranking.getBusName())
                        .number(ranking.getNumber())
                        .build());
            }
            // 汇总
            long count = rankings.stream().mapToLong(HandleRanking::getNumber).sum();
            return Result.succeed(data, "获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("办件量排名分析失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 评价分析
     *
     * @param query
     * @return
     */
    public Result appraiseStatistics(StatisticsQuery query) {
        List<Map<String, Long>> data = new ArrayList<>();
        if(StringUtils.isBlank(query.getBusinessId())){
            query.setUserid("%"+UserUtils.getUser().getId()+"%");
        }
        try {
            List<AppraiseType> appraiseTypes = appraiseMapper.selectAppraiseType();
            // 新增未评价类型，如有其他数据库未记录类型，可在appraiseTypes中继续add
            if (CollectionUtil.isEmpty(appraiseTypes)) {
                return Result.succeed("获取成功！");
            }
            List<AppraiseCount> appraiseCounts = appraiseMapper.statistics(query);
            Map<Integer, AppraiseCount> appraiseCountsMap = appraiseCounts.stream().collect(Collectors.toMap(AppraiseCount::getLevel, Function.identity()));
            for (AppraiseType appraiseType : appraiseTypes) {
                Map<String, Long> map = new HashMap<>();
                AppraiseCount count = appraiseCountsMap.get(appraiseType.getLevel());
                long number = 0L;
                if (null != count) {
                    number = count.getNumber();
                }
                map.put(appraiseType.getName(), number);
                data.add(map);
            }
            //汇总
            long count = appraiseCounts.stream().mapToLong(AppraiseCount::getNumber).sum();
            return Result.succeed(data, "获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("评价分析失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 平均等待时间统计
     *
     * @param query
     * @return
     */
    public Result<List<WaitingTimeVO>> avgWaitingTimeStatistics(StatisticsQuery query) {
        List<WaitingTimeVO> data = new ArrayList<>();
        // 平均等待时长(分钟)上限
        query.setUserid("%"+UserUtils.getUser().getId()+"%");
        int avgTimeUpperLimit = 1;
        try {
            List<WaitingTimeCount> avgsTimes = waitingTimeMapper.avgTimeStatistics(query);
            avgsTimes = avgsTimes.stream().filter(e -> StringUtils.isNotEmpty(e.getBusName()) || avgTimeUpperLimit < e.getAvgTime()).collect(Collectors.toList());
            List<WaitingTimeCount> notProcessed = waitingTimeMapper.notProcessed(query);
            Map<String, WaitingTimeCount> notDataMap = notProcessed.stream().collect(Collectors.toMap(WaitingTimeCount::getSerialId, Function.identity()));
            for (WaitingTimeCount datum : avgsTimes) {
                if(datum.getDoTime() <= 0){
                    datum.setDoTime(1);
                }
                List<String> counterNo = counterService.findCounterNoBySerialNo(SerialUtils.buildSerial(datum.getSerialNo(), 3), query.getAreaId());
                WaitingTimeVO waitObj = WaitingTimeVO.builder().avgTime(datum.getAvgTime())
                        .doTime(datum.getDoTime())
                        .busName(datum.getBusName())
                        .busChar(datum.getBusChar())
                        .processedCount(datum.getNumber())
                        .counters(counterNo.stream().map(e -> e + "号").collect(Collectors.joining(" ")))
                        .build();

                Optional.ofNullable(notDataMap.get(datum.getSerialId())).ifPresent(e -> waitObj.setNotProcessedCount(e.getNumber()));
                data.add(waitObj);
            }
            return Result.succeed(data, "获取成功！");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("排号等待时间统计失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 平均办理时间统计
     *
     * @param query
     * @return
     */
    public AjaxJson avgWinTime(StatisticsQuery query) {
        // 平均等待时长(分钟)上限
        int avgTimeUpperLimit = 100;
        query.setUserid("%"+UserUtils.getUser().getId()+"%");
        List<WaitingTimeCount> avgsTimes = waitingTimeMapper.avgWinTime(query);
        Collections.sort(avgsTimes);
        for (WaitingTimeCount datum : avgsTimes) {
            if (datum.getDoTime() <= 0) {
                datum.setDoTime(1);
            }
            if (datum.getAvgTime() <= 0) {
                datum.setDoTime(1);
            } else if (datum.getAvgTime() >= avgTimeUpperLimit) {
                datum.setDoTime(avgTimeUpperLimit);
            }
            datum.setWinName(datum.getWinName()+"号窗口");
        }
        return AjaxJson.success("获取成功！").put("data",avgsTimes);
    }

    /**
     * 时段人流量分析
     * 小时
     *
     * @param query
     * @return
     */
    public Result<StatisticsXY> timePeriodTraffic(StatisticsQuery query) {
        List<String> xValue = new ArrayList<>();
        List<Long> yValue = new ArrayList<>();
        try {
            // 时段(小时)上限
            int upperLimit = 17;
            // 时段下限
            int lowerLimit = 9;
            query.setUserid("%"+UserUtils.getUser().getId()+"%");
            List<TimePeriodTrafficCount> timePeriodTrafficCounts = timePeriodTrafficMapper.statistics(query);
            timePeriodTrafficCounts = timePeriodTrafficCounts.stream().filter(e ->
                    upperLimit >= e.getTimePeriod() && lowerLimit <= e.getTimePeriod()).collect(Collectors.toList());
            for (TimePeriodTrafficCount timePeriodTrafficCount : timePeriodTrafficCounts) {
                xValue.add(timePeriodTrafficCount.getTimePeriod() + "点-" + (timePeriodTrafficCount.getTimePeriod() + 1) + "点");
                yValue.add(timePeriodTrafficCount.getNumber());
            }
            //汇总
            long count = timePeriodTrafficCounts.stream().mapToLong(TimePeriodTrafficCount::getNumber).sum();
            return Result.succeed(new StatisticsXY(xValue, yValue), "获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("时段人流量统计失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 周人流量分析
     * 周
     *
     * @param query
     * @return
     */
    public Result<StatisticsXY> weeklyTraffic(StatisticsQuery query) {
        List<String> xValue = new ArrayList<>();
        List<Long> yValue = new ArrayList<>();
        try {
            query.setUserid("%"+UserUtils.getUser().getId()+"%");
            List<WeeklyTrafficCount> weeklyTrafficCounts = weeklyTrafficMapper.statistics(query);
            for (WeeklyTrafficCount weeklyTrafficCount : weeklyTrafficCounts) {
                xValue.add("第" + NumberUtil.numberToZh(weeklyTrafficCount.getWeekDay()) + "周");
                yValue.add(weeklyTrafficCount.getNumber());
            }
            //汇总
            long count = weeklyTrafficCounts.stream().mapToLong(WeeklyTrafficCount::getNumber).sum();
            return Result.succeed(new StatisticsXY(xValue, yValue), "获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("周人流量统计失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }

    /**
     * 办理人员接件统计
     *
     * @param query
     * @return
     */
    public Result<StatisticsXY> staffPiecesReceived(StatisticsQuery query) {
        List<String> xValue = new ArrayList<>();
        List<Long> yValue = new ArrayList<>();
        try {
            query.setUserid("%"+UserUtils.getUser().getId()+"%");
            List<StaffPiecesReceivedCount> staffPiecesReceivedCounts = staffPiecesReceivedMapper.statistics(query);
            for (StaffPiecesReceivedCount staffPiecesReceivedCount : staffPiecesReceivedCounts) {
                xValue.add(staffPiecesReceivedCount.getStaffName());
                yValue.add(staffPiecesReceivedCount.getNumber());
            }
            //汇总
            long count = staffPiecesReceivedCounts.stream().mapToLong(StaffPiecesReceivedCount::getNumber).sum();
            return Result.succeed(new StatisticsXY(xValue, yValue), "获取成功！", ImmutableMap.of(Constant.AJAX_JSON_COUNT, count));

        } catch (Exception e) {
            e.printStackTrace();
            log.error("办理人员接件统计失败->{}", e.getMessage());
        }
        return Result.failed("统计失败，请联系管理员！");
    }


    /**
     * 转换参数
     *
     * @param query
     * @return
     * @throws Exception
     */
    private void convertParams(StatisticsQuery query) {
        if(null == query.getStartTime() || null == query.getEndTime() || null != query.getCurrentFlag()){
            return;
        }
        // 同一年
        boolean isSameYear = DateUtil.isSameYear(DateUtils.parseDate(query.getStartTime()), DateUtils.parseDate(query.getEndTime()));
        // 同一年
        boolean isSameMonth = DateUtil.isSameMonth(DateUtils.parseDate(query.getStartTime()), DateUtils.parseDate(query.getEndTime()));
        if(!isSameYear){
            query.setCurrentFlag(QueryParamsEnum.CURRENT_LAST_YEAR.getCode());
        }
        if(isSameYear && !isSameMonth){
            query.setCurrentFlag(QueryParamsEnum.CURRENT_YEAR.getCode());
        }
    }
}
